#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctime>
#include <string>
#include <vector>
#include <iostream>
#include "task.hpp"

const int process_count = 10;

class channel;
std::vector<channel> ProcessPool;

class channel
{
public:
    channel(int fd, pid_t SlaveId, int masterId, std::string& SlaveName)
        :_fd(fd), _SlaveId(SlaveId), _masterId(masterId), _SlaveName(SlaveName)
    { }

public:
    int _fd;
    pid_t _SlaveId;
    pid_t _masterId;
    std::string _SlaveName;
};

void ChildDoTask()
{
    int taskNo = 0;
    while(true)
    {
        ssize_t s = read(0, &taskNo, sizeof(taskNo));
        if(s > 0)
        {
            std::cout << "Child get a task -- taskNo:" << taskNo << std::endl;
            taskList[taskNo]();
        }
        else if(s == 0) { break; }
        else { perror("ChildDoTask:read err"); exit(1); }
    }
}

void InitProcessPool()
{
    srand(time(nullptr));
    std::vector<int> oldfds;
    for(int i = 0; i < process_count; ++i)
    {
        int pipefd[2];
        int ret = pipe(pipefd); if(ret < 0) { perror("InitProcessPool:pipe err"); exit(1); }
        int id = fork();
        if(id < 0) { perror("InitProcessPool:fork err"); exit(1); }
        else if(id == 0)
        {
            for(auto fd : oldfds) { close(fd); }
            close(pipefd[1]);
            dup2(pipefd[0], 0);
            ChildDoTask();
            exit(0);
        }
        else
        {
            close(pipefd[0]);
            std::string SlaveName = "Slave No." + std::to_string(i);
            ProcessPool.push_back(channel(pipefd[1], id, getpid(), SlaveName));
            oldfds.push_back(pipefd[1]);
        }
    }
}

void TaskAllocation(int taskNo)
{
    //考虑子进程的负载均衡：随机channel
    int ChannelNo = rand() % process_count;
    channel slaveChannel = ProcessPool[ChannelNo];
    int no = taskNo;
    write(slaveChannel._fd, &no, sizeof(taskNo));
    std::cout << "Father allocate a task complete -- taskNo:" << taskNo << std::endl;
}

void ProcessDestroy()
{
    for(int i = 0; i < process_count; ++i) {
        close(ProcessPool[i]._fd);
        std::cout << "channel fd closed -- fd:" << ProcessPool[i]._fd << std::endl;
    }
    //sleep(5);
    for(int i = 0; i < process_count; ++i) {
        waitpid(ProcessPool[i]._SlaveId, nullptr, 0);
        std::cout << "child clean -- pid:" << ProcessPool[i]._SlaveId << std::endl;
    }
    //sleep(5);
}

int main()
{
    InitProcessPool();
    int cnt = 5;
    while(cnt--)
    {
        int taskNo = rand() % 5;
        TaskAllocation(taskNo);
        sleep(1);
    }
    ProcessDestroy();
    // TaskAllocation(0);
    // TaskAllocation(2);
    //ProcessDestroy();
    //TaskAllocation(1);
    //dubug
    // for(int i = 0; i < process_count; ++i)
    // {
    //     std::cout << "process fd:" << ProcessPool[i]._fd << 
    //         " -- process id:" << ProcessPool[i]._SlaveId << 
    //         " -- father id:" << ProcessPool[i]._masterId <<
    //         " -- process Name:" << ProcessPool[i]._SlaveName << std::endl;
    // }
    return 0;
}